/**
 * @file Shell.java
 * Projet eCOM 2010 (Miage Descartes)
 * @author Doido Sébastien
 * @version 2
 * @brief Shell : Gestion des beans au travers d'un programme shell
 */
package ecom.shell;

import ecom.beans.EcomAdminRemote;
import ecom.beans.EcomCustomerRemote;
import ecom.beans.EuroConvertorBean.Currency;
import java.io.*;
import java.util.TreeMap;
import java.io.PrintStream;
import javax.ejb.Remote;
import javax.ejb.Stateful;

/**
 * @brief Shell : Gestion des beans au travers d'un programme shell
 * @author Sebastien
 */
@Stateful
@Remote(ShellRemote.class)
public class Shell implements ShellConstantes, ShellRemote {

    private TreeMap _commandNameMap = new TreeMap();
    private TreeMap _commandNameHelp = new TreeMap();
    private ShellContext _context = new ShellContextImpl(_commandNameMap, _commandNameHelp);
    private boolean stop = false;
    private boolean admin = false;
    protected InputStream in;
    protected PrintStream out;
    protected PrintStream err;

    public Shell() {
        out = System.out;
        err = System.err;
        in = System.in;
    }

    /**
     * @brief Initialise le shell
     * @param customerBean : bean remote client
     * @param adminBean : bean remote admin
     * @param adminMode : mode admin ou pas
     */
    public void load(EcomCustomerRemote customerBean, EcomAdminRemote adminBean, boolean adminMode) {
        this.admin = adminMode;
        
        ShellContext context = getContext();
        addCommand(new EchoCommandImpl(context));

        addCommand(new CategoryCommandImpl(context));
        addCommand(new AccountCommandImpl(context));
        addCommand(new StoreCommandImpl(context));
        addCommand(new ProductCommandImpl(context));
        addCommand(new CurrencyCommandImpl(context));
        addCommand(new LanguageCommandImpl(context));
        addCommand(new OutputCommandImpl(context));
        
        addCommand(new BatchCommandImpl(context));

            addCommand(new PauseCommandImpl(context));
            addCommand(new BeginTxCommandImpl(context));
            addCommand(new CommitCurrentTxCommandImpl(context));
            addCommand(new RollbackCurrentTxCommandImpl(context));
            addCommand(new CartCommandImpl(context));
       

        addCommand(new HelpCommandImpl(context));
        addCommand(new SimpleQuitCommandImpl(context));

        // put the EBs' homes in the context
        context.setVar(PROMPT, "->");
        context.setVar(BANNER, getBanner());
        context.setVar("adminMode", adminMode);

        context.setVar("adminBean", adminBean);
        context.setVar("customerBean", customerBean);
        context.setVar("currency", Currency.getDefault());
        context.setVar("language", LanguageCommandImpl.Languages.getDefault());
        context.setVar("output", OutputCommandImpl.Outputs.getDefault());
        context.setVar("shellMaster", this);
    }

    /**
     * @brief renvoie le contexte du shell
     * @return le contexte du shell
     */
    protected final ShellContext getContext() {
        return _context;
    }

    /**
     * @brief Stop le shell
     */
    protected final void stop() {
        stop = true;
    }

    /**
     * @brief Renvoie la banniere du shell
     * @return la banniere du shell
     */
    public String getBanner() {
        StringBuffer sb = new StringBuffer();
        sb.append("\n-------------------------------------------------");
        sb.append("\n| eCOM Shell by Sébatien Doido                  |");
        sb.append("\n| Shell mode : [" + (admin ? " Admin  " : "Customer") + "]                       |");
        sb.append("\n-------------------------------------------------");
        return sb.toString();
    }

    /**
     * @brief Execution d'une commande par le shell
     * @param commandLine : commande à exécuter
     * @return
     * @throws java.lang.Exception
     */
    public String executeCommand(String commandLine) throws Exception {
        return executeCommand(commandLine, out, err);
    }
    
    /**
     * @brief exécution de la commande
     * @param commandLine : commande
     * @param out : flux d'affichage std
     * @param err : flux d'affichage err
     * @return les données à afficher
     * @throws java.lang.Exception
     */
    protected final synchronized String executeCommand(String commandLine, PrintStream out, PrintStream err) throws Exception {
        commandLine = commandLine.trim();
        String commandName = (commandLine.indexOf(' ') >= 0) ? commandLine.substring(0, commandLine.indexOf(' ')) : commandLine;
        ShellCommand command = getCommand(commandName);
        if (command != null) {
            return command.execute(commandLine, out, err);
        } else {
            err.println("Command not found.");
        }
        return "";
    }

    /**
     * @brief Retourne un objet ShellCommand pour une commande de type chaîne de caractère
     * @param name : nom de la commande
     * @return un objet ShellCommand pour une commande de type chaîne de caractère
     */
    protected final synchronized ShellCommand getCommand(String name) {
        ShellCommand sc = (ShellCommand) _commandNameMap.get(name);
        return sc;
    }

    /**
     * @brief Déclare une nouvelle commande pour le shell
     * @param sc : nouvelle commande à reconnaître
     */
    protected final synchronized void addCommand(ShellCommand sc) {
        String[] cmd = sc.getName().split("\\|");
        for (String tag : cmd) {
            _commandNameMap.put(tag, sc);
        }
        _commandNameHelp.put(sc.getName(), sc);
    }
}
